home *** CD-ROM | disk | FTP | other *** search
- A Tcl Binding to Motif
-
- Jan Newmarch
- University of Canberra
-
- Introduction
-
- The X Window System is now accepted as the standard windowing systems for
- Unix graphics workstations and terminals. It provides a low-level set of
- tools to build applications. Most applications now are built using a
- higher-level toolkit which typically supplies objects usually known as
- widgets. There are a number of such toolkits, but the one that has achieved
- the major success is the Motif toolkit based on the Xt Intrinsics. Motif
- has defined a look-and-feel that is copied to a greater or lesser extent by
- other toolkits, and forms a component of specifications such as COSE.
-
- The specification for Motif basically assumes a C-like language, and the
- only implementation of that specification is the C library from OSF. This
- has led to many bindings to this library from alternative systems. These
- include even higher-level systems that can be ported across different
- window systems, to specific language bindings. These include C++, Ada,
- Prolog, Lisp, Poplog and the Korn Shell.
-
- Tcl (Tool Command Language) is a type-free interpreted language that was
- designed to be embedded into applications requiring a command language for
- communication with users, to parse specification files requiring
- language complexity, and to provide a macro language for applications such
- as spreadsheets. The intent was to do it right once, so that
- application-writers need not invent their own language and write their own
- parsers and semantic evaluators.
-
- Tcl has been extended with an X Window toolkit not based on the Intrinsics,
- that supplies a set of widgets directly accessible from tcl. This Tk
- toolkit is generally run from a program called ``wish'' that sets up a
- suitable environment and then calls an event processing loop for the Tk
- widgets.
-
- However, there are differences between Tk and Motif, some minor and some
- major. These differences are no better nor worse than the differences
- between other toolkits such as InterViews, but do seem to give
- rise to some heated debate at times. For example, there is the claim that
- Motif must be slower than Tk because of the complexity of implementation
- above Xt. On the other hand, it must be faster because Tcl/Tk is
- interpreted. Tcl/Tk programs are often pointed at as significantly shorter
- than equivalent Motif programs, without determining whether this difference
- is caused by choice of language - C versus Tcl, or choice of toolkit -
- Motif versus Tk. Other issues such as the complexity of Motif XmStrings
- against their value for internationalisation are often discussed.
-
- This paper reports on a project that attempts to remove some of the
- variables from this debate. It provides a binding of Tcl to Motif so that
- Tcl programs can be written directly using the Motif C libraries. This
- binding is by a library of C functions called Tm (Tcl Motif). The focus
- in this paper is on the mechanisms of this implementation, but some
- discussion is given to the language against toolkit debate.
-
- Recently the author became aware of the Wafe system, which was a binding
- of the Athena widgets to tcl. This project had different aims to this
- one, but there are many common elements. This is also discussed.
-
- Elements of tcl
-
- Elements of Motif
-
- Elements of Tk
-
- The moat Interpreter
-
- Tm borrows heavily from Tk in many places. Tk has an interpreter called
- ``wish'' (Window Shell) that sets up the Tk world, sources a Tcl/Tk file
- and then enters a Tk event processing loop. This is sufficiently general
- that many useful Tk programs can be written just using ``wish'' as
- application environment. Problems requiring a richer environment may use a
- modified ``wish''.
-
- Tm uses this idea and supplies an interpreter called ``moat'' (MOtif And Tcl)
- This sets up an Xt world by calling XtAppInitialize, creates a
- Tcl interpreter, sources a Tcl file, realizes all widgets and then enters
- the Xt event loop.
-
- Creating Widgets
-
- Widgets are created using Tcl commands registered with the Tcl interpreter
- on initialisation. These creation commands follow the design of the Tk
- system, in that there is one creation command per class of widget. In
- addition, Motif has a set of dialogs, which are convenience routines for
- creating a compound widget in a way that is supposed to be invisible to the
- C programmer and act as though they create single objects. These routines
- are also implemented as widget creation functions in Tm. It is not hard to
- ``special case'' some functions within Tm to handle these dialogs.
- Motif also ``special cases'' two common operations - creating a ScrolledList
- and a ScrolledText widget. This is also handled by Tm. In both of these
- special cases, the parent is brought into the Tm system, and is given a
- unique name. This name is produced from the pathname by introducing an
- extra dot into the path.
-
- Widget Commands
-
- When a widget is created two major things occur: an Xt/Motif widget is
- created and a command with the widget name is added to the Tcl interpreter.
- This gives an object-oriented flavour to the system in that a widget becomes
- a command which is interpreted as an object with methods.
-
-
- Widget Methods
-
- Each widget has a set of methods applicable to it. In general, most widgets
- inherit from TmCore. This allows Xt methods such as ManageChild and
- UnmanageChild to be handled from one function. The design of Tcl registers
- a command handler per command; widgets that have no special methods simply
- register the TmCore handler. Widgets with more methods register a different
- handler which may call TmCore eventually in an inheritance chain.
-
- Each widget in fact has special methods: the callback procedures for that
- class. This is handled by TmCore rather than in individual command handlers
- because of regularities in the implementation of Motif that are better
- discussed in the next section. Briefly, each callback can be recognised because
- it ends in the string ``Callback''. This can then be added to the Xt widget
- callbacks using XtAddCallback in the TmCore handler, without worrying about
- exactly which callback it is.
-
- In C, when a callback is added to a widget a specific C function is
- specified that will be invoked when the action for that callback occurs.
- However, we want a Tcl function to be executed. This is easily done by
- using a generic C callback function that handles every widget, almost
- without exception. When a callback is added in Xt, the ClientData field is
- set to point to a structure containing the Tcl interpreter and the string
- that is the Tcl callback function. This gives the generic C callback
- fucntion enough information to execute the Tcl function.
-
- Resource Converters
-
- The presence of resource converters within Xt is the key to the ease with
- which this binding has been implemented. Previous sections have used
- existing Tcl/Tk concepts (and code) to a large extent. It is now time for
- Xt to play a significant part. Xt allows users to store resource values in
- files such as .Xdefaults to control run-time values for the program. This
- user-level control is one of the major features of Xt. The resource files
- contain strings representing the values the user wants. For example, a
- width may be set to the string "200". Xt, and all toolkits built above it,
- supply ``resource converters'' to transform these string values into the
- internal data types required by the program.
-
- To perform such conversions, Xt supplies a number of useful functions.
- XtGetResourceList and XtGetConstraintList return lists of resources
- applicable to each class of widget. Elements in these lists are structures
- that contain strings representing the source and destination types, and
- the size (in bytes) of the destination type. The string representations
- allow searches for source types, and the structure when located in the list
- provides enough information to call XtConvertAndStore. This looks up a list
- of registered converters and calls the converter function if found.
-
- This makes one side of this binding trivially simple: if a resource can be
- specified in a resource file then a converter exists from string to
- internal value. The Tcl setValues function simply has to locate the
- resource in these resource lists and call XtConvertAndStore. It can then use
- XtSetValues to install the converted value, and Xt and Motif do the rest!
-
- This also makes the naming conventions in tcl very easy. Because resources
- are specified as strings, the names can be used by tcl without change.
- Motif is quite consistent in its use of these names (alphabetic only,
- beginning with a lower case letter, and with other words in the name
- capitalised). Tk uses this convention as well, so the similarity in
- programs across the two systems is maintained.
-
- Well, it isn't really trivial. Some resources require widget values, such
- as edge bindings in Form. Tm needs to supply another converter, from
- TmWidgetName to Xt Widget. This, and similar needs are answered by just
- adding more converters. A more serious problem is addressed in the next
- section.
-
- The largest amount of work in this binding is in implementing getValues.
- This requires conversion from internal type to strings. For many types
- such as Dimension there is no support from either Xt or Motif. However,
- for enumerated types such as arrowDirection for the ArrowButton widget,
- Motif not only gives ``Representation Type'' converters for conversion
- from String to enumerated type, but also allows converters in the reverse
- direction to be installed, so that names such as ``arrow_left' can be
- generated. This was intended for GUI building systems which need to use
- symbolic names when setting or getting widget values, but it suits tcl
- very well, thank you.
-
- Secondary Resources
-
- Xt allows objects to have subobjects. There are not many examples of these.
- Editors with Output subobjects and Input subobjects are the principal
- ones. The nasty part is that these subobjects can have their own
- resources and Xt supplies no means for an application to access them.
- Xt has a ``hook'' to allow the toolkit library to access them, but not the
- application (in Motif at any rate they are static to a file, so there is no
- direct way of accesing them). Fortunately, Motif (not Xt) supplies
- the function XmGetSecondaryResources to get these.
-
- Special Cases
-
- Convenience functions
-
- {Scrolled List, Dialogs}
- Motif supplies convenience functions of several types. Some such as the
- various RowColumn functions of XmCreateMenuBar, XmCreateOptionMenu, etc
- just set extra parameters for RowColumn and are easy to handle. Two other
- sets are the ScrolledObject functions such as XmCreateScrolledList and
- XmCreateScrolledText and the Dialog convenience functions such as
- XmCreateFormDialog etc. Both of these sets of functions create a pair
- of widgets, not just a single one. For example, XmCreateScrolledList
- creates a ScrolledWindow parent and the List child, whereas the Dialog
- functions create a Popup shell parent. In all cases, the Create function
- returns the child widget.
-
- The intent in Motif was to hide the parent widgets. Unfortunately it canot be
- done completely for several reasons. Firstly, when the ScrolledList (or any
- of the others) is destroyed, it is the parent that must be destroyed, not
- just the child. Otherwise a memory leak occurs. Secondly, when you need to
- set constraint resources (such as placing the ScrolledList into a Form), it
- is the parent widget that needs resources set, not the child. Thus a
- mechanism to access the parent is required.
-
- In Motif, this may be done by the call XtParent, which returns the Xt
- widget parent. In this binding it is neccessary to return a tcl widget
- parent, and this may be a problem. The tcl parent must be generated
- automatically, but must be guaranteed unique. Otherwise there may be an
- accidental name collision with other tcl widgets. The Motif naming
- mechanism (tacking ``SW'' onto Scrolled Objects, ``_popup'' onto dialogs)
- does not guarantee this. Fortunately, the particular naming syntax used in
- this binding (based on Tk), where widget names are separated by dots ``.''
- does allow this, by inserting an extra dot. For example,
-
- scrolledList .l
- puts stdout [.l parent]
-
- produces the unique `..l''.
-
- Timing conversions
-
- Some resources can only be set at creation time. Such resources are of two
- types: the first is exemplified by ... in which the value of this resource
- is used during the Initialize function and is thereafter unused. The second
- is one that cannot be changed because it has too many ramifications. Such
- a resource is the ScrollingPolicy of the ScrolledWindow widget. These
- resources must be converted from their String value to be used in the Args
- array to the XmCreate... function.
-
- On the other hand, some resources use widget values in their calculation.
- For example, any Dimension or Position resource such as the width uses the
- Motif UnitType resource in its calculation, in order to gain independance
- of the display size characteristics. Similarly, the LabelPixmap resource of
- Labels needs to have a foreground and background before it can be created.
-
- These differing cases cause a problem. The convertor functions from String
- to Value use a widget parameter, and in the first case this can only be the
- parent (as the child Create function cannot have been called yet) whereas
- in the second it requires the widget itself. The special case code to
- handle this is not only a maintainance problem, but is not guaranteed to be
- correct in the first place as neither Motif nor Xt offer any support to
- distinguish the cases (the recently released WKSH also faced this problem
- and missed the LabelPixmap case, probably because it is quite well hidden
- in the Motif source).
-
- This binding divides the resources into ones which must be converted before
- creation, those that must be converted after creation, and those for which
- it does not matter. These are all handled correctly. A case which is not
- handled is where the conversion must be done during creation.
- Fortunately this does not occur, as it would break any bindings such as
- this one that rely on the resource converter mechanism.
-
- XmStringTables
-
- Various widgets such as ScrolledList use XmStringTables, which are arrays
- of XmStrings. Motif is inconsistent in its internal use of these arrays -
- sometimes they are NULL-terminated, most times they are not. This means
- that there is no way of determining from the XmStringtable itself exactly
- how many elements it contains. This must be found from other means. For
- example, the size of the List resource ``items'' is found in the List
- resource ``itemCount'', and the size of the ``selectedItems'' resource is
- found in the `selectedItemsCount'' resource. When an XmStringTable is
- converted into a String, this size must be known to the resource converter.
- This could be determined from the widget type and resource name (eg for
- ``items'' of a List widget, determine it from ``itemCount''), but the
- resource name is not available to the resource converter. Thus special case
- code must be inserted before any resource converter can be called, just in
- case it is one of these cases. This is inelegant and an overhead in time
- for all of the resource conversions, whatever type.
-
- Text Verify Callbacks
-
- Motif callbacks provide extra information through the callback data. This
- is generally a pointer to a structure specific to the widget type. Fro
- example, the PushButton callback structure contains a field ``click_count''
- to allow distinction between single and multiple clicks. Generally these
- structures contain ``read only'' information that is not to be modified.
-
- The Text widget has a set of ``verify'' callbacks that point to read/write
- structures. The purpose of these is to allow for things such as password
- entry, where the application needs to be given the characters typed in, but
- must be able to signal to Text not to echo these characters. This is done
- by setting the ``doit'' field in the XmTextVerifyCallbackStruct to False.
- These calllbacks are actually called by Motif in an unusual way: for
- example, when characters are typed in Motif decodes the characters, calls
- the modifyVerifyCallbacks, examines the return state of the callback
- structure and only then actually inserts (or not) the characters typed.
-
- This is handled by creating a global variable and passing its name (rather
- than its value) into the callback. The application can then modify its
- value, and this is used to set the Motif fields as appropriate. The Motif
- mechanism is odd in this respect, and the tcl binding shows this in
- practice.
-
- Inconsistencies and Bugs
-
- By and large tcl and Motif work well together. One area that does not integrate
- perfectly concerns lists. In Motif there are sometimes lists of XmStrings, and
- when they are represented as strings individual elements are separated by
- commas. tcl on the other hand represents lists as elements separated by
- whitespace. Both handle lists containing whitespace in different ways, with
- the tcl solution being more general. Motif would have (say for a list of
- authors of Motif books)
-
- Dan Heller, Jan Newmarch, Thomas Berlage
-
- tcl would have
-
- {Dan Heller} {Jan Newmarch} {Thomas Berlage}
-
-
- Hiding Complexity
-
- One of the hurdles in any Xt program is the complexity of concepts in even
- a trivial program. The Tk library hides parts of this by placing initialisation
- and the event loop handler into the ``wish'' intepreter, and by making the
- callback mechanism simpler. The Tm library copies most of this, and so achieves
- the same simplicity in this respect.
-
- Motif adds further layers of complexity above this. A particularly tricky
- hurdle to overcome is the support for internationalisation offered by
- XmStrings. The Tm library handles XmStrings internally, and uses the normal
- tcl String mechanism for all purposes. Thus this mechanism is hidden from
- the tcl programmer. It is still present in Motif, so a Label widget can
- display Japanese text as specified in a resource file. The ability of tcl to
- manage this is still in doubt (it is at least 8-bit clean, and Tk can use the
- X11 support to display ISO 8859-1 characters).
-
- Validation
-
- The Tm library is built on Motif. Can it be certified as Motif compliant?
- Well, actually, no. This is basically a library into Motif, and as such
- must be compliant with the AES (Application Environment Specification).
- The AES details what functions a Motif library must make available, and this
- binding falls short of that. For example, Tm hides XmStrings and has no
- explicit support for them. So it fails the test of ``coverage'' as you can't
- do everything in Tm that you can using the OSF C library.
-
- On the other hand, applications built using this library can be certified
- as Motif compliant. Application compliance just means that *out of the
- elements of GUI used*, these conform to the Motif Style Guide. You can
- really muck up a Tm application by putting the menu bar at the bottom, with
- the Help button on the left and even worse things, and these will fail to
- give you Motif compliance, but if you aren't that silly you will be able
- to get Motif certification for applications built using Tm.
-
-
- Wafe and WKSH
-
- The WKSH is a binding of the Korn Shell to Motif. It deals with the same
- problems as this binding, in that it has to convert Strings to Motif types.
- It appears to use the same mechanisms, and has run into the same problems.
- For example, it handles the Conversion versus Creation problem for
- resources such as width by disallowing setting of such
- resources during creation! In this binding it is deferred until it is
- valid. The lack of support by Xt and Motif in this area is evidenced by the
- failure of the WKSH to correctly handle the LabelPixmap resource in its
- initial release.
-
- WKSH models itself on the syntax of the Motif C language binding. The
- function calls use the same names, such as XmCreateMainWindow. The binding
- also partly preserves the positional syntax of the C language, so that a C call
-
- w = XmCreateLabel(parent, name, args, argc)
-
- becomes
-
- XmCreateLabel parent w name args...
-
- The WKSH binding actually adds an extra argument to replace the return value of
- the function, and uses the varargs style of argument passing that has
- become quite popular within the X world.
-
- The WKSH binding follows this even further in defining functions such as
- XtManageChildren which place the action followed by arguments.
-
- The Wafe binding follows this same principle of action followed by object,
- but without the positional argument complexity of WKSH. This particular
- binding seems to have suffered confused press in that it produces a Tcl
- binding to Xt on one side, and an open-ended binding of Tcl/Xt to
- almost any language on the other. This generality seems to have led to
- impressions such as "it is a way of writing Perl programs that use Tcl to
- talk to Xt". The current status of Wafe is that it binds Tcl to a variety
- of Xt-based widget libraries, with Athena being well supported, and Motif
- in beta. The Wafe callback model is very different to Tm. In Tm, the Motif
- style is followed in that the callback contains useful information and
- helps to give the ``feel'' part of the ``look and feel'' paradigm. Wafe
- uses a limited set of callbacks to produce popup dialogs.
-
- In implementation, the Wafe and Tm systems follow very similar lines as
- there is really only one way of doing much of the binding of Xt toolkits to
- string languages such as Tcl and Ksh. The authors of Wafe suffer the problem
- of only having access to Motif
- 1.1 at the time of writing, so the additional aids supplied in Motif 1.2
- are not available to them. This is a distinct drawback. I am in active email
- correspodence with them, to avoid duplicating work.
-